#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os

from common.common import check_del_dir, execute_cmd
from common.const import CMDResult
from common.logger import Logger
from db2.comm.const import Db2Const
from db2.comm.db2_exception import ErrCodeException
from db2.comm.error_code import Db2ErrCode
from db2.comm.util.common_util import Db2CommonUtil
from db2.comm.util.param_util import Db2ParamUtil

LOGGER = Logger().get_logger(filename="db2.log")


class HaUtil:
    @staticmethod
    def handle_mount_path_for_san(os_user, param_dict: dict, ori_mount_path_list: list):
        """
        SAN Client场景处理将副本初始挂载目录再挂载到新目录
        :param os_user: 操作系统用户名
        :param param_dict: 任务参数字典
        :param ori_mount_path_list: 初始副本挂载目录列表
        :return: 最终副本挂载目录列表
        """
        use_san_client = Db2ParamUtil.use_san_client_for_restore(param_dict)
        if not use_san_client:
            return ori_mount_path_list
        # 恢复时副本目录要求不超过215个字符，否则会报SQL2543N错误，SAN Client场景需要将初始挂载目录再挂载到较短的新目录
        job_id = Db2ParamUtil.get_job_id(param_dict)
        # powerHA SAN Client场景副本最终挂载路径
        last_mount_dir = os.path.join(Db2Const.MOUNT_PATH, f"DB2_{job_id}")
        last_mount_path_list = list()
        for idx, ori_mount_path in enumerate(ori_mount_path_list):
            # powerHA SAN Client场景副本最终挂载路径
            tgt_mount_path = os.path.join(last_mount_dir, "data", str(idx))
            Db2CommonUtil.mount_path_on_aix(ori_mount_path, tgt_mount_path)
            last_mount_path_list.append(tgt_mount_path)
        grp_name = Db2CommonUtil.get_group_name_by_os_user(os_user)
        chown_cmd = f"chown -R {os_user}:{grp_name} {last_mount_dir}"
        LOGGER.info(f"Executing chown last data mount path command: {chown_cmd}.")
        return_code, out, err = execute_cmd(chown_cmd)
        if return_code != CMDResult.SUCCESS.value:
            LOGGER.error(f"Execute chown last data mount path command failed, "
                         f"return code: {return_code}, out: {out}, err: {err}.")
            raise ErrCodeException(Db2ErrCode.FAILED_EXECUTE_COMMAND, *[chown_cmd, out])
        LOGGER.info("Execute chown last data mount path command success.")
        return last_mount_path_list

    @staticmethod
    def handle_mount_path_for_san_ts(os_user, param_dict: dict, ori_mount_path_list: list):
        """
        SAN Client场景处理将副本初始挂载目录再挂载到新目录
        :param os_user: 操作系统用户名
        :param param_dict: 任务参数字典
        :param ori_mount_path_list: 初始副本挂载目录列表
        :return: 最终副本挂载目录列表
        """
        use_san_client = Db2ParamUtil.use_san_client_for_restore(param_dict)
        if not use_san_client:
            return ori_mount_path_list
        # 恢复时副本目录要求不超过215个字符，否则会报SQL2543N错误，SAN Client场景需要将初始挂载目录再挂载到较短的新目录
        job_id = Db2ParamUtil.get_job_id(param_dict)
        # powerHA SAN Client场景副本最终挂载路径
        last_mount_dir = os.path.join(Db2Const.MOUNT_PATH, f"DB2_{job_id}")
        for idx, ori_mount_path in enumerate(ori_mount_path_list):
            # powerHA SAN Client场景副本最终挂载路径
            tgt_mount_path = os.path.join(last_mount_dir, "data", str(idx))
            src_path = ori_mount_path.get("data_path")[0]
            Db2CommonUtil.mount_path_on_aix(src_path, tgt_mount_path)
            ori_mount_path["data_path"] = [tgt_mount_path]
        grp_name = Db2CommonUtil.get_group_name_by_os_user(os_user)
        chown_cmd = f"chown -R {os_user}:{grp_name} {last_mount_dir}"
        LOGGER.info(f"Executing chown last data mount path command: {chown_cmd}.")
        return_code, out, err = execute_cmd(chown_cmd)
        if return_code != CMDResult.SUCCESS.value:
            LOGGER.error(f"Execute chown last data mount path command failed, "
                         f"return code: {return_code}, out: {out}, err: {err}.")
            raise ErrCodeException(Db2ErrCode.FAILED_EXECUTE_COMMAND, *[chown_cmd, out])
        LOGGER.info("Execute chown last data mount path command success.")
        return ori_mount_path_list

    @staticmethod
    def handle_unmount_path_for_san(param_dict):
        """
        SAN Client场景清理临时挂载目录
        :param param_dict: 任务参数字典
        :return:
        """
        use_san_client = Db2ParamUtil.use_san_client_for_restore(param_dict)
        if not use_san_client:
            return
        job_id = Db2ParamUtil.get_job_id(param_dict)
        # powerHA SAN Client场景副本最终挂载路径
        last_mount_dir = os.path.join(Db2Const.MOUNT_PATH, f"DB2_{job_id}")
        mount_path = os.path.join(last_mount_dir, "data")
        if not os.path.exists(mount_path):
            LOGGER.error(f"umount path does not exist: {mount_path}")
            return
        for i in os.listdir(mount_path):
            real_path = os.path.join(mount_path, i)
            if not os.path.isdir(real_path):
                continue
            Db2CommonUtil.umount_path_on_aix(real_path)
        check_del_dir(last_mount_dir)
        LOGGER.info("Delete powerHA last data copy mount path success.")
